home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Copyright (c) 1998 D. Richard Hipp
- **
- ** This program is free software; you can redistribute it and/or
- ** modify it under the terms of the GNU General Public
- ** License as published by the Free Software Foundation; either
- ** version 2 of the License, or (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ** General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public
- ** License along with this program; if not, write to the
- ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- ** Boston, MA 02111-1307, USA.
- **
- ** Author contact information:
- ** drh@acm.org
- ** http://www.hwaci.com/drh/
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <termios.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdarg.h>
- #include <string.h>
- #include <signal.h>
- #include <sys/wait.h>
-
- /*
- ** Names of files and executables and other hard-coded
- ** strings.
- */
- #define DB_DIR "/var/eznet"
- #define DB_FILE DB_DIR "/eznet.conf"
- #define PPP_DIR "/etc/ppp"
- #define PPP_EXE "/usr/sbin/pppd"
- #define SELF "/usr/bin/eznet"
- #define DIALD_EXE "/usr/sbin/diald"
- #define SESSIONLOG DB_DIR "/session.html"
-
- /*
- ** The following define determines what version of PPP
- ** this program expects by default. You can override this
- ** value using the pppversion= parameter.
- */
- #define DFLT_PPP_VERSION "2.3"
-
- /*
- ** Each entry in the database is represented in memory by an instance
- ** of the following structure.
- */
- typedef struct ConfEntry ConfEntry;
- struct ConfEntry {
- char *zLabel; /* A label for this entry */
- ConfEntry *next; /* Next entry in the same record */
- char *zValue; /* Value for this entry */
- };
-
- /*
- ** These variables record the whole database. There are nRecord
- ** records, and each record consists of a linked list of ConfEntry
- ** structures where aRecord[N] points to the head of the list for
- ** record number N.
- */
- static int nRecord = 0; /* Number of records */
- static ConfEntry **aRecord = 0; /* List of ConfEntries for each record */
-
- /*
- ** A transcript of the CHAT session is written to this file, if
- ** it is open.
- */
- static FILE *transcript = 0;
-
- /*
- ** If this is a set-uid or set-gid process, then release all
- ** privileges.
- */
- static void Unprivileged(void){
- int uid = getuid();
- int gid = getgid();
- setregid(gid,gid);
- setreuid(uid,uid);
- }
-
- /*
- ** Read the entire contents of a file into memory. Space to
- ** hold the file is obtained from malloc. NULL is returned if
- ** we can't read the file for any reason.
- */
- static char *ReadFile(const char *zFilename){
- int fd;
- FILE *in;
- int toread;
- int read;
- int n;
- char *zBuf;
- struct stat sbuf;
-
- in = fopen(zFilename,"r");
- if( in==0 ) return 0;
- fd = fileno(in);
- if( fstat(fd, &sbuf)!=0 ){
- fclose(in);
- return 0;
- }
- toread = sbuf.st_size;
- read = 0;
- zBuf = malloc( toread+1 );
- if( zBuf==0 ){
- fclose(in);
- return 0;
- }
- while( toread && (n=fread(&zBuf[read],1,toread,in))>0 ){
- toread -= n;
- read += n;
- }
- zBuf[read] = 0;
- fclose(in);
- return zBuf;
- }
-
- /* Change the status for a record. The status is recorded in
- ** a file named
- **
- ** /var/eznet/status.NNN
- **
- ** where NNN is the record number.
- */
- static void WriteStatus(int iRec, char *zStatus, ...){
- FILE *out;
- va_list ap;
- char zFilename[sizeof(DB_DIR)+20];
-
- sprintf(zFilename,"%s/status.%d",DB_DIR,iRec);
- out = fopen(zFilename,"w");
- if( out ){
- time_t now;
- struct tm *p;
- char zBuf[200];
- fchown(fileno(out),0,0);
- fchmod(fileno(out),0644);
- va_start(ap, zStatus);
- vfprintf(out,zStatus,ap);
- va_end(ap);
- time(&now);
- p = localtime(&now);
- strftime(zBuf,sizeof(zBuf)-1," %I:%M%p %a %b %d, %Y\n", p);
- fprintf(out,zBuf);
- fclose(out);
- }
- }
-
- /* Write a status report from Chat. This is written to a file
- ** named
- **
- ** /var/eznet/chatstat.NNN
- **
- ** where NNN is the record number.
- */
- static void WriteChatStat(int iRec, char *zStatus, ...){
- FILE *out;
- va_list ap;
- char zFilename[sizeof(DB_DIR)+20];
-
- sprintf(zFilename,"%s/chatstat.%d",DB_DIR,iRec);
- out = fopen(zFilename,"w");
- if( out ){
- va_start(ap, zStatus);
- vfprintf(out,zStatus,ap);
- va_end(ap);
- fclose(out);
- }
- }
-
- /*
- ** Write text into a file. zFile is the name of the file into
- ** which the text is written. zFormat is a printf-like format
- ** string that defines the text. The owner of the file is converted
- ** to root and the permissions are set to "mode".
- */
- static void WriteToFile(char *zFile, int mode, char *zFormat, ...){
- FILE *out;
- va_list ap;
-
- out = fopen(zFile,"w");
- if( out==0 ) return;
- fchmod(fileno(out),mode);
- fchown(fileno(out),0,0);
- va_start(ap,zFormat);
- vfprintf(out,zFormat,ap);
- va_end(ap);
- fclose(out);
- }
-
- /* Make sure /etc/ppp/ip-up and /etc/ppp/ip-down invoke eznet
- ** with either the "ipup" or "ipdown" argument (as approprite.)
- ** This is needed so that we can adjust the status when the link
- ** goes up or down.
- */
- static void SetIpUpDown(char *zUpDown){
- char *zText;
- int i;
- int lineLen = 0;
- int patLen;
- char zPat[100];
- char zFile[sizeof(PPP_DIR)+20];
-
- sprintf(zFile,"%s/ip-%s",PPP_DIR,zUpDown);
- zText = ReadFile(zFile);
- if( zText==0 ){
- WriteToFile(zFile, 0744,
- "#!/bin/sh\n" SELF " ip%s $* &\n", zUpDown);
- return;
- }
- for(i=0; zText[i] && zText[i]!='\n'; i++){}
- if( zText[i]=='\n' ){
- lineLen = i;
- }
- sprintf(zPat,SELF " ip%s $* &",zUpDown);
- patLen = strlen(zPat);
- while( zText[i] && (zText[i]!='/' || strncmp(&zText[i], zPat, patLen)) ){
- i++;
- }
- if( zText[i]==0 ){
- WriteToFile(zFile, 0744, "#!/bin/sh\n%s\n%s",
- zPat, &zText[lineLen]);
- }
- }
-
- /*
- ** Parse a single line of the pap-secrets or chap-secrets file whose
- ** text begins as *pzText. The elements of the line are place in
- ** azArgs[0] through azArgs[3].
- **
- ** After parsing, *pzText is left pointing to the first character
- ** after then end of the parsed text. At end of file, *pzText points
- ** to 0.
- **
- ** All of azArgs[0] through azArgs[3] are always filled in. Empty
- ** strings are inserted if necessary. A comment line is placed in
- ** azArgs[0] and the others are empty strings.
- **
- ** Quotes and escapes are removed from azArgs[0] through azArgs[2],
- ** except for comment lines which are passed through unaltered.
- */
- static void GetSecret(char **pzText, char **azArgs){
- int i;
- char *z = *pzText;
- while( isspace(*z) ) z++;
- azArgs[0] = azArgs[1] = azArgs[2] = azArgs[3] = "";
- if( *z=='#' ){
- azArgs[0] = z;
- while( *z && *z!='\n' ) z++;
- if( *z=='\n' ){
- *z = 0;
- z++;
- }
- *pzText = z;
- return;
- }
- for(i=0; i<=2; i++){
- int hasEscape = 0;
- azArgs[i] = z;
- if( *z=='"' ){
- azArgs[i]++;
- z++;
- while( *z && *z!='"' ){
- if( *z=='\\' && z[1] ){ z++; hasEscape = 1; }
- z++;
- }
- if( *z=='"' ){
- *z = 0;
- z++;
- }
- }else{
- while( *z && !isspace(*z) ){
- if( *z=='\\' && z[1] ){ z++; hasEscape = 1; }
- z++;
- }
- if( *z ){
- *z = 0;
- z++;
- }
- }
- while( isspace(*z) && *z!='\n' ){ z++; }
- if( hasEscape ){
- int j = 0, k = 0;
- char *zStr = azArgs[i];
- while( zStr[j] ){
- if( zStr[j]=='\\' && zStr[j+1] ){ j++; }
- zStr[k++] = zStr[j++];
- }
- }
- }
- azArgs[i] = z;
- while( *z && *z!='\n' ){
- if( *z=='\\' && z[1] ){ z++; }
- z++;
- }
- if( *z=='\n' ){
- *z = 0;
- z++;
- }
- *pzText = z;
- }
-
- /*
- ** The elements azArgs[0] through azArgs[3] contain the text of
- ** a secret. This secret is written to *pzBuf. *pzBuf is updated
- ** to point to the null terminator at the end of the written text.
- **
- ** Quotes and escapes are inserted on azArgs[0] through azArgs[2]
- ** if needed. Except if the first character of azArgs[0] is "#"
- ** then no quotes or escapes are inserted.
- */
- static void AppendSecret(char **pzBuf, char **azArgs){
- char *z = *pzBuf;
- char *zSrc;
- int i;
- if( azArgs[0][0]=='#' ){
- zSrc = azArgs[0];
- while( *zSrc ){ *(z++) = *(zSrc++); }
- *(z++) = '\n';
- *z = 0;
- *pzBuf = z;
- return;
- }
- for(i=0; i<=2; i++){
- zSrc = azArgs[i];
- if( *zSrc==0 ) continue;
- while( *zSrc ){
- switch( *zSrc ){
- case ' ':
- case '\t':
- case '\n':
- case '"':
- case '\\':
- *(z++) = '\\';
- /* Fall thru */
- default:
- *(z++) = *(zSrc++);
- break;
- }
- }
- *(z++) = ' ';
- }
- while( *zSrc ){ *(z++) = *(zSrc++); }
- *(z++) = '\n';
- *z = 0;
- *pzBuf = z;
- }
-
- /* Make sure the correct password for the service and user is found in the
- ** secrets file. Add it if is not. Preserve any commands or
- ** unrelated secrets that are previously found in the file.
- **
- ** Needless to say, we have to have root privileges to run
- ** this function successfully. The secrets files contain information
- ** which should not be publicly viewable.
- */
- static void SetSecrets(
- char *zBase, /* Either "pap-secrets" or "chap-secrets" */
- char *zService, /* Name of the service provider we are calling */
- char *zUser, /* Our login name */
- char *zPassword /* Our password */
- ){
- char *zOld, *zOldOrig;
- char *z;
- char *zNew;
- int extra;
- int seenServiceUser = 0;
- int seenUserService = 0;
- char *azArgs[4];
- char zFile[sizeof(PPP_DIR)+20];
-
- if( zPassword==0 || zUser==0 || zService==0 || zFile==0 ) return;
- sprintf(zFile,"%s/%.15s",PPP_DIR,zBase);
- zOldOrig = zOld = ReadFile(zFile);
- extra = (strlen(zService) + strlen(zPassword) + strlen(zUser) + 10)*4;
- if( zOld==0 ){
- zNew = malloc( extra + 100 );
- sprintf(zNew,"#\n%s %s %s\n%s %s %s\n",
- zService, zUser, zPassword,
- zUser, zService, zPassword
- );
- WriteToFile(zFile, 0600, zNew);
- free(zNew);
- return;
- }
- z = zNew = malloc( strlen(zOld) + extra + 100 );
- if( z==0 ) return;
- while( zOld && *zOld ){
- GetSecret(&zOld, azArgs);
- if( azArgs[0][0]!='#' ){
- if( strcmp(azArgs[0],zService)==0 && strcmp(azArgs[1],zUser)==0 ){
- seenServiceUser = 1;
- azArgs[2] = zPassword;
- azArgs[3] = "";
- }else if( strcmp(azArgs[0],zUser)==0 && strcmp(azArgs[1],zService)==0 ){
- seenUserService = 1;
- azArgs[2] = zPassword;
- azArgs[3] = "";
- }
- }
- AppendSecret(&z, azArgs);
- }
- if( !seenServiceUser ){
- azArgs[0] = zService;
- azArgs[1] = zUser;
- azArgs[2] = zPassword;
- azArgs[3] = "";
- AppendSecret(&z, azArgs);
- }
- if( !seenUserService ){
- azArgs[0] = zUser;
- azArgs[1] = zService;
- azArgs[2] = zPassword;
- azArgs[3] = "";
- AppendSecret(&z, azArgs);
- }
- WriteToFile(zFile, 0600, zNew);
- free(zOldOrig);
- free(zNew);
- }
-
- /* zFile[*pI] is the first character in a line of text. Return
- ** a pointer to the first non-whitespace character in this line.
- ** Also convert the \n into a \0 and make *pI be the index of
- ** the first character on the next line.
- **
- ** If zFile[*pI] is 0, then we've reached the end of input.
- ** Return NULL.
- */
- static char *GetLine(char *zFile, int *pI){
- int i = *pI;
- int iStart;
- if( zFile[i]==0 ) return 0;
- while( isspace(zFile[i]) ){ i++; }
- iStart = i;
- while( zFile[i] && zFile[i]!='\n' ){ i++; }
- if( zFile[i] ){
- zFile[i] = 0;
- *pI = i+1;
- }else{
- *pI = i;
- }
- return &zFile[iStart];
- }
-
- /* This array maps hexadecimal digit values into their numeric
- ** value.
- */
- static int hexval[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
- 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- };
-
- /* Return a pointer to the first space-separated token past
- ** the character zLine[*pI]. Return NULL if there are no more
- ** tokens. *pI is left pointing to the first character after
- ** the token.
- **
- ** The HTTP-style encoding is removed from the token and the
- ** token is null-terminated.
- */
- static char *GetToken(char *zLine, int *pI){
- int i = *pI;
- int iStart;
- int j;
- while( isspace(zLine[i]) ){ i++; }
- if( zLine[i]==0 ) return 0;
- iStart = i;
- while( zLine[i] && !isspace(zLine[i]) ){ i++; }
- if( zLine[i] ){
- *pI = i + 1;
- zLine[i] = 0;
- }else{
- *pI = i;
- }
- for(i=j=iStart; zLine[i]; i++){
- switch( zLine[i] ){
- case '+':
- zLine[j++] = ' ';
- break;
- case '%':
- if( zLine[i+1] && zLine[i+2] ){
- zLine[j++] = hexval[0x7f & zLine[i+1]]*16 + hexval[0x7f & zLine[i+2]];
- i += 2;
- }else{
- zLine[j++] = '%';
- }
- break;
- default:
- zLine[j++] = zLine[i];
- break;
- }
- }
- zLine[j] = 0;
- return &zLine[iStart];
- }
-
- /*
- ** This function inserts a new entry into the database (or replaces
- ** the value of an existing entry). iRec is the record number.
- ** New records are created as necessary. zField is the entry label,
- ** and zValue is its value. Both are plain text.
- **
- ** If zValue==0 or *zValue==0, then the entry is deleted.
- **
- ** Memory to hold the new entry is obtained from malloc.
- */
- static void InsertEntry(int iRec, char *zLabel, char *zValue){
- ConfEntry *p;
- if( zValue==0 || *zValue==0 ){
- if( iRec>=0 && iRec<nRecord ){
- ConfEntry **pp = &aRecord[iRec];
- while( (p=*pp)!=0 ){
- if( strcmp(p->zLabel,zLabel)==0 ) break;
- pp = &p->next;
- }
- if( p ){
- *pp = p->next;
- free( p->zValue );
- free( p );
- }
- }
- return;
- }
- if( iRec>=nRecord ){
- if( nRecord==0 ){
- aRecord = malloc( sizeof(ConfEntry*)*(iRec+1) );
- }else{
- aRecord = realloc( aRecord, sizeof(ConfEntry*)*(iRec+1) );
- }
- if( aRecord==0 ){ nRecord = 0; return; }
- while( nRecord<=iRec ){
- aRecord[nRecord++] = 0;
- }
- }
- for(p=aRecord[iRec]; p; p=p->next){
- if( strcmp(p->zLabel,zLabel)==0 ) break;
- }
- if( p==0 ){
- p = malloc( sizeof(ConfEntry) + strlen(zLabel) + 1 );
- if( p==0 ) return;
- p->zLabel = (char*)&p[1];
- strcpy(p->zLabel, zLabel);
- p->next = aRecord[iRec];
- p->zValue = 0;
- aRecord[iRec] = p;
- }
- if( p ){
- if( p->zValue ) free(p->zValue);
- p->zValue = malloc( strlen(zValue) + 1 );
- if( p->zValue ) strcpy(p->zValue, zValue);
- }
- }
-
- /*
- ** The set of characters that need to be excaped are coded as "1".
- ** Safe characters are 0.
- */
- static unsigned char NeedEsc[] = {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- };
-
- /* Do an HTTP-style encoding of zToken and write it on the
- ** output file given.
- */
- static void WriteToken(FILE *out, char *zToken){
- int i = 0;
- while( zToken[i] ){
- if( !NeedEsc[(unsigned)zToken[i]&0xff] ){
- i++;
- }else{
- if( i>0 ){
- fwrite(zToken,1,i,out);
- }
- if( zToken[i]==' ' ){
- fwrite("+",1,1,out);
- }else{
- char zBuf[4];
- zBuf[0] = '%';
- zBuf[1] = "0123456789ABCDEF"[(zToken[i]>>4)&0xf];
- zBuf[2] = "0123456789ABCDEF"[zToken[i]&0xf];
- zBuf[3] = 0;
- fwrite(zBuf,1,3,out);
- }
- zToken += i + 1;
- i = 0;
- }
- }
- if( i>0 ){
- fwrite(zToken,1,i,out);
- }
- }
-
- /*
- ** The set of characters that need to be excaped like "\012" are
- ** are coded as 1. Safe characters are 0. Characters that need
- ** a backslash in front are coded with 2. Another code generates
- ** a symbolic escape by putting a backslash in front of the value.
- */
- static unsigned char NeedTclEsc[] = {
- 1, 1, 1, 1, 1, 1, 1, 'a', 'b','t','n', 1, 'f','r', 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 0, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- };
-
- /* Write a string as a single TCL token.
- */
- static void WriteTcl(FILE *out, char *z){
- register c;
- while( (c=*(z++))!=0 ){
- if( NeedTclEsc[c] ){
- int e = NeedTclEsc[c];
- if( e==1 ){
- fprintf(out,"\\%03o",0xff&c);
- }else if( e==2 ){
- fprintf(out,"\\%c",c);
- }else{
- fprintf(out,"\\%c",e);
- }
- }else{
- putc(c,out);
- }
- }
- }
-
- /*
- ** The set of characters that need to be excaped like "\012" are
- ** are coded as 1. Safe characters are 0. Characters that need
- ** a backslash in front are coded with 2. Another code generates
- ** a symbolic escape by putting a backslash in front of the value.
- */
- static unsigned char NeedHumanEsc[] = {
- 1, 1, 1, 1, 1, 1, 1, 'a', 'b','t','n', 1, 'f','r', 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- };
-
- /* Write a string as a single TCL token.
- */
- static void WriteHumanReadable(FILE *out, char *z){
- register c;
- while( (c=*(z++))!=0 ){
- if( NeedHumanEsc[c] ){
- int e = NeedHumanEsc[c];
- if( e==1 ){
- fprintf(out,"\\%03o",0xff&c);
- }else if( e==2 ){
- fprintf(out,"\\%c",c);
- }else{
- fprintf(out,"\\%c",e);
- }
- }else{
- putc(c,out);
- }
- }
- }
-
- /*
- ** Convert a non-negative number from its ASCII form into a binary
- ** form. Return -1 if the input string is not a non-negative number.
- */
- static int GetInt(char *z){
- int v = 0;
- while( *z ){
- if( *z<'0' || *z>'9' ) return -1;
- v = v*10 + *(z++) - '0';
- }
- return v;
- }
-
- /*
- ** Read the whole database into memory.
- */
- static void ReadDb(void){
- char *zDb;
- int i,j;
- char *zLine;
- char *zToken;
- int iRec;
- char *zField;
- char *zValue;
-
- zDb = ReadFile(DB_FILE);
- if( zDb==0 ) return;
- i = 0;
- while( (zLine=GetLine(zDb,&i))!=0 ){
- if( *zLine=='#' ) continue;
- j = 0;
- zToken = GetToken(zLine,&j);
- if( zToken==0 ) continue;
- iRec = GetInt(zToken);
- if( iRec<0 ) continue;
- zField = GetToken(zLine,&j);
- zValue = GetToken(zLine,&j);
- if( zValue==0 ) continue;
- InsertEntry(iRec,zField,zValue);
- }
- free( zDb );
- }
-
- /* Given two lists of ConfEntry structures both of which are
- ** sorted and either or both of which can be empty, combine the
- ** two lists into a single sorted list. Return a pointer to
- ** the head of the new list.
- **
- ** This is part of the merge-sort algorithm.
- */
- static ConfEntry *merge(ConfEntry *left, ConfEntry *right){
- ConfEntry *head = 0, *tail = 0;
- while( left && right ){
- int c = strcmp(left->zLabel, right->zLabel);
- if( c<0 ){
- if( tail ){
- tail->next = left;
- tail = tail->next;
- }else{
- head = tail = left;
- }
- left = left->next;
- tail->next = 0;
- }else{
- if( tail ){
- tail->next = right;
- tail = tail->next;
- }else{
- head = tail = right;
- }
- right = right->next;
- tail->next = 0;
- }
- }
- if( left ){
- if( tail ){
- tail->next = left;
- }else{
- head = tail = left;
- }
- }else if( right ){
- if( tail ){
- tail->next = right;
- }else{
- head = tail = right;
- }
- }
- return head;
- }
-
- /* Sort a list of ConfEntry structures. Return a pointer to
- ** the sorted list.
- **
- ** The algorithm is merge-sort.
- */
- static ConfEntry *sort(ConfEntry *p){
- int i;
- ConfEntry *pNext;
- ConfEntry *a[32];
-
- for(i=0; i<sizeof(a)/sizeof(a[0]); i++){ a[i] = 0; }
- while( p ){
- pNext = p->next;
- p->next = 0;
- for(i=0; a[i] && i<sizeof(a)/sizeof(a[0])-1; i++){
- p = merge(a[i],p);
- a[i] = 0;
- }
- a[i] = p;
- p = pNext;
- }
- for(i=0; i<sizeof(a)/sizeof(a[0]); i++){
- p = merge(p,a[i]);
- }
- return p;
- }
-
- /*
- ** Write the entire database back to the disk. Make sure the
- ** database file is owned by root and has 0600 permissions so
- ** that unprivileged users can't see the passwords.
- */
- static void WriteDb(void){
- FILE *out;
- int i;
- ConfEntry *p;
- int fd;
- char zFilename[sizeof(DB_FILE)+100];
-
- sprintf(zFilename,"%s.%d",DB_FILE,getpid());
- out = fopen(zFilename,"w");
- if( out==0 ) return;
- fd = fileno(out);
- fchmod(fd,0600);
- fchown(fd,0,0);
- for(i=0; i<nRecord; i++){
- aRecord[i] = p = sort(aRecord[i]);
- for(p=aRecord[i]; p; p=p->next){
- fprintf(out,"%d %s ",i,p->zLabel);
- WriteToken(out,p->zValue);
- fprintf(out,"\n");
- }
- }
- fclose(out);
- unlink(DB_FILE);
- link(zFilename,DB_FILE);
- unlink(zFilename);
- }
-
- /*
- ** Given a sequence of strings of the form
- **
- ** LABEL=VALUE
- **
- ** parse the strings up into LABEL and VALUE and add entries
- ** for each string to the database as record iRec.
- */
- static void AddEntries(int iRec, int argc, char **argv){
- int i, j;
- char *zLabel;
- char *zValue;
- for(i=0; i<argc; i++){
- zLabel = argv[i];
- for(j=1; zLabel[j] && zLabel[j]!='='; j++){}
- if( zLabel[j]!='=' ) continue;
- zLabel[j] = 0;
- zValue = &zLabel[j+1];
- InsertEntry(iRec, zLabel, zValue);
- }
- }
-
- /*
- ** Rearrange the order of records so that the Mth record
- ** becomes the Nth record.
- */
- static void MoveRecord(int M, int N){
- int i;
- ConfEntry *pTemp;
-
- if( nRecord<0 ) return;
- if( M>=nRecord ) M = nRecord-1;
- if( M<0 ) M = 0;
- if( N>=nRecord ) N = nRecord-1;
- if( N<0 ) N = 0;
- if( M==N ) return;
- if( M<N ){
- pTemp = aRecord[M];
- for(i=M; i<N; i++){
- aRecord[i] = aRecord[i+1];
- }
- aRecord[N] = pTemp;
- }else{
- pTemp = aRecord[M];
- for(i=M; i>N; i--){
- aRecord[i] = aRecord[i-1];
- }
- aRecord[N] = pTemp;
- }
- }
-
- /*
- ** Return TRUE if the given string is an IP address composed of
- ** 4 numbers between 0 and 255 separated by dots. If the string
- ** is an IP address, return the value in *pIp.
- */
- static int IsIpAddr(char *z, int *pIp){
- int a1, a2, a3, a4, rc;
- if( sscanf(z,"%d.%d.%d.%d",&a1,&a2,&a3,&a4)==4
- && a1>=0 && a1<=255
- && a2>=0 && a2<=255
- && a3>=0 && a3<=255
- && a4>=0 && a4<=255
- ){
- *pIp = (a1<<24) | (a2<<16) | (a3<<8) | a4;
- rc = 1;
- }else{
- rc = 0;
- }
- return rc;
- }
-
- /*
- ** Look up a specific field in a specific record and return its
- ** value. Return the given default value if it is not found.
- */
- static char *Lookup(int iRec, char *zLabel, char *zDflt){
- ConfEntry *p;
- if( iRec<0 || iRec>=nRecord ) return zDflt;
- for(p=aRecord[iRec]; p; p=p->next){
- if( strcmp(zLabel,p->zLabel)==0 ) return p->zValue;
- }
- return zDflt;
- }
-
- /*
- ** Given a command-line parameter that might be a record number,
- ** or an IP address, or a modem tty name, or the keyword "all",
- ** return a record number. The special code FIND_ERROR is returned
- ** if we can't find a match. FIND_ALL is returned if the keyword
- ** "all" appears or for a NULL string.
- */
- #define FIND_ALL -1
- #define FIND_ERROR -2
- static int FindRecord(char *z){
- int i;
- int ip;
-
- if( z==0 ){
- if( nRecord==1 ) return 0;
- return FIND_ALL;
- }
- if( strcmp(z,"all")==0 ){
- return FIND_ALL;
- }
- i = GetInt(z);
- if( i>=0 ){
- if( i>=nRecord ) i = nRecord-1;
- if( i<0 ) i = 0;
- return i;
- }
- if( IsIpAddr(z,&ip) ){
- int t, mask, iRec;
- char *zVal;
- for(iRec=0; iRec<nRecord; iRec++){
- zVal = Lookup(iRec,"ip","0.0.0.0");
- if( !IsIpAddr(zVal,&t) ) continue;
- zVal = Lookup(iRec,"netmask","0.0.0.0");
- if( !IsIpAddr(zVal,&mask) ) continue;
- if( (t&mask)==(ip&mask) ) return iRec;
- }
- }
- if( z[0]=='/' ){
- int iRec;
- char *zVal;
- for(iRec=0; iRec<nRecord; iRec++){
- zVal = Lookup(iRec,"tty","/dev/modem");
- if( strcmp(zVal,z)==0 ) return iRec;
- }
- }
- for(i=0; i<nRecord; i++){
- char *zVal = Lookup(i,"service",0);
- if( zVal && strcmp(zVal,z)==0 ) return i;
- }
- return FIND_ERROR;
- }
-
- /*
- ** Write a timestamp on the transcript.
- */
- static void WriteTimestamp(void){
- struct timeval stv;
- struct timezone stz;
- if( transcript==0 ) return;
- gettimeofday(&stv,&stz);
- fprintf(transcript,"%02ld:%02ld.%03ld", (long)(stv.tv_sec/60)%60,
- (long)stv.tv_sec % 60, (long)stv.tv_usec/1000);
- }
-
- /*
- ** Write to a file descriptor, and also to the transcript.
- */
- static void ChatWrite(char *z, int shroud){
- int n, w;
- if( transcript ){
- if( shroud>0 ){
- int i = strlen(z);
- while( i>0 ){
- fprintf(transcript,"%.*s",i,"**********" "**********" "***********");
- i -= 30;
- }
- }else{
- WriteHumanReadable(transcript,z);
- }
- }
- n = strlen(z);
- while( n ){
- w = write(1, z, n);
- if( w>0 ){
- n -= w;
- z += w;
- }
- }
- }
-
- /*
- ** Send output to the modem.
- **
- ** Delay for "delay" microseconds before actually doing the write.
- ** This is for modems that get fouled up by input that follows to
- ** closely after their own output.
- **
- ** The transmitted text is normally written to the transcript file.
- ** But if "shroud" is one, then "*" characters are subsitituted.
- ** This is used when writting the password, to keep it from view.
- */
- static void ChatSend(int delay, int shroud, char *z, ...){
- va_list ap;
- if( z==0 ) return;
- if( delay>0 ){
- usleep(delay);
- }
- if( transcript ){
- WriteTimestamp();
- fprintf(transcript," Send: \"");
- }
- va_start(ap, z);
- ChatWrite(z, shroud);
- while( (z = va_arg(ap,char*))!=0 ){
- ChatWrite(z, shroud);
- shroud--;
- }
- if( transcript ){
- fprintf(transcript,"\"\n");
- fflush(transcript);
- }
- }
-
- /*
- ** Read text from the input and put it into zBuf. Reading continues
- ** until:
- **
- ** * No characters are received after waiting for "timeout"
- ** seconds, or
- **
- ** * Some characters have been received but no characters have
- ** appeared for 500 milliseconds or more.
- **
- ** Only characters since the last new-line are returned in zBuf.
- ** But all received characters are written to the transcript.
- **
- ** Characters in zBuf[] when this routine is called are not erased
- ** or overwritten. Newly read characters are appended. Unless
- ** a new-line or carriage routine is seen, when all characters are
- ** deleted.
- **
- ** The function returns the number of characters that were received
- ** during the current call to this function. This number will be
- ** zero if a timeout occurs.
- */
- static int ChatRecv(char *zBuf, int nBuf, int timeout){
- int n; /* Number of bytes returned from a single read() */
- int i; /* Loop counter */
- int idle = 0; /* Number of 1/10ths of second since last read() */
- int got; /* How many characters previously read */
- int nChar = 0; /* Total number of characters read */
-
- time_t start;
- time_t now;
-
- /* Remember when we began looking... */
- time(&start);
-
- /* Figure out how much text is already in zBuf[]. New
- ** text will be appended.
- */
- for(got=0; zBuf[got]; got++){}
- if( got>0 && (zBuf[got-1]=='\n' || zBuf[got-1]=='\r') ){ got = 0; }
- zBuf[got] = 0;
-
- /* Start reading input...
- */
- while( got<nBuf-1 && (nChar==0 || idle<5) ){
- time(&now);
- if( start+timeout < now ) break;
- n = read(0, &zBuf[got], nBuf-1-got);
- if( n<0 ) n = 0;
- nChar += n;
- if( n==0 ){
- usleep(100000);
- idle++;
- continue;
- }
- zBuf[got+n] = 0;
- idle = 0;
- got += n;
-
- /* Remove any characters that are followed by a '\n'. Except,
- ** don't remove characters if the '\n' is followed by nothing
- ** unless '\n' is on a line by itself or preceded by a single
- ** '\r'.
- */
- for(i=0; i<got; i++){
- if( zBuf[i]=='\n' && (zBuf[i+1]!=0 || i==0 || (i==1 && zBuf[0]=='\r')) ){
- if( transcript ){
- int c;
- WriteTimestamp();
- fprintf(transcript," Skip: \"");
- c = zBuf[i+1];
- zBuf[i+1] = 0;
- WriteHumanReadable(transcript,zBuf);
- zBuf[i+1] = c;
- fprintf(transcript,"\"\n");
- fflush(transcript);
- }
- strcpy(zBuf, &zBuf[i+1]);
- got -= i+1;
- i = -1;
- }
- }
- }
- if( transcript && zBuf[0] ){
- WriteTimestamp();
- fprintf(transcript," Recv: \"");
- WriteHumanReadable(transcript,zBuf);
- fprintf(transcript,"\"\n");
- fflush(transcript);
- }
- return nChar;
- }
-
- /*
- ** Return true if zPattern occurs anywhere in zBuf
- */
- static int Match(char *zBuf, char *zPattern){
- int len = strlen(zPattern);
- while( *zBuf ){
- if( *zBuf==*zPattern && strncmp(zBuf,zPattern,len)==0 ){
- if( transcript ){
- WriteTimestamp();
- fprintf(transcript," Match: \"");
- WriteHumanReadable(transcript,zPattern);
- fprintf(transcript,"\"\n");
- fflush(transcript);
- }
- return 1;
- }
- zBuf++;
- }
- return 0;
- }
-
- /*
- ** The following array maps 8-bit characters into 7-bit characters
- ** and upper-case into lower-case.
- */
- static unsigned char SevenBit[] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
- 112,113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95,
- 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
- 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
- 128, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
- 112,113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95,
- 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
- 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
- };
-
- /*
- ** Compare two strings. In the first string, use only the lower
- ** 7 bits and convert all upper case to lower case letters.
- */
- static int StrNCmp7(char *zBuf, char *zPattern, int n){
- while( n-- ){
- int a = SevenBit[(int)*((unsigned char*)zBuf++)];
- int b = (int)*((unsigned char*)zPattern++);
- if( a==0 || b==0 || a!=b ){ return a - b; }
- }
- return 0;
- }
-
- /*
- ** Like Match(), but only uses the lower seven 7 bits of zBuf
- ** and treats all characters in zBuf as lower-case.
- */
- static int Match7(char *zBuf, char *zPattern){
- int len = strlen(zPattern);
- while( *zBuf ){
- if( SevenBit[*(unsigned char*)zBuf]==*zPattern
- && StrNCmp7(zBuf,zPattern,len)==0 ){
- if( transcript ){
- WriteTimestamp();
- fprintf(transcript," Match: \"");
- WriteHumanReadable(transcript,zPattern);
- fprintf(transcript,"\"\n");
- fflush(transcript);
- }
- return 1;
- }
- zBuf++;
- }
- return 0;
- }
-
- /*
- ** Return TRUE if the input line looks like a prompt of some kind.
- ** A "prompt" is a seqence of words followed by a colon, or perhaps
- ** something like "->".
- */
- static int IsPrompt(char *zLine){
- int i;
- for(i=0; zLine[i]!=0 && zLine[i]!='\n' && zLine[i]!='\r'; i++){}
- while( i>0 && isspace(zLine[i-1]) ){ i--; }
- i--;
- if( i<=0 ) return 0;
- if( zLine[i]==':' ) return 1;
- if( zLine[i]=='?' ) return 1;
- if( zLine[i]=='>' ) return 1;
- if( zLine[i]=='$' ) return 1;
- return 0;
- }
-
- #define MAX_TIME 70 /* Maximum time to connect */
- #define DIAL_TIMEOUT "60" /* How long to wait for dialing to complete */
- #define CHAT_TIMEOUT "3" /* How long to wait for responses after dialing */
-
- /* This routine is pretty much the whole point. Assuming a
- ** modem is connected on file descriptors 0 and 1, initialize
- ** the modem, dial the phone number, supply user ID and password
- ** (if requested). Return successfully (0) if we see the start of
- ** PPP communication and return an error (1) if anything goes
- ** wrong.
- **
- ** This routine runs as root so that it will have permission
- ** to open the output file associated with WriteChatStat().
- */
- static int Chat(int iRec){
- struct termios tio_0_saved;
- struct termios tio_1_saved;
- struct termios tio_new;
- int flags;
- int i;
- char *zVal;
- int timeout;
- int dial_timeout;
- int nTimeout = 0;
- time_t start, now;
- int rc = 4;
- int chatDelay = 0;
- char *zChat;
- char *zPhone;
- char *zExpect[10];
- char *zReply[10];
- char zLine[1000];
-
- tcgetattr(0,&tio_0_saved);
- tcgetattr(1,&tio_1_saved);
- tio_new = tio_0_saved;
- cfmakeraw(&tio_new);
- tcsetattr(0,TCSANOW,&tio_new);
- tio_new = tio_1_saved;
- cfmakeraw(&tio_new);
- tcsetattr(1,TCSANOW,&tio_new);
- flags = fcntl(0, F_GETFL);
- fcntl(0, F_SETFL, O_NONBLOCK);
-
- sprintf(zLine,"%s/transcript.%d",DB_DIR,iRec);
- transcript = fopen(zLine,"a");
- if( transcript ){
- fchmod(fileno(transcript),0644);
- fchown(fileno(transcript),0,0);
- }
-
- zChat = Lookup(iRec,"chat","yes");
- chatDelay = atoi(Lookup(iRec,"delay","0"))*1000;
- for(i=0; i<=9; i++){
- static char *dfltInit[10] = { "atz", "at&d3", };
- sprintf(zLine,"init%d",i);
- zVal = Lookup(iRec,zLine,dfltInit[i]);
- if( zVal ){
- ChatSend(chatDelay,0,zVal,"\r",0);
- zLine[0] = 0;
- ChatRecv(zLine,sizeof(zLine),1000);
- if( !Match(zLine,"OK") ){
- ChatRecv(zLine,sizeof(zLine),1000);
- }
- }
- sprintf(zLine,"expect%d",i);
- zExpect[i] = Lookup(iRec,zLine,0);
- sprintf(zLine,"reply%d",i);
- zReply[i] = Lookup(iRec,zLine,0);
- }
- zPhone = Lookup(iRec,"phone",0);
- if( zPhone==0 ){
- WriteChatStat(iRec,"No phone number specified");
- return 1;
- }
- ChatSend(chatDelay,0,"atd", zPhone, "\r", 0);
- timeout = dial_timeout = atoi(Lookup(iRec,"dialtimeout",DIAL_TIMEOUT));
- time(&start);
- zLine[0] = 0;
- nTimeout = 0;
- while( 1 ){
- int nChar = ChatRecv(zLine,sizeof(zLine),timeout);
- time(&now);
- if( now-start > MAX_TIME ){
- WriteChatStat(iRec,"Login timeout at");
- break;
- }
- if( zLine[0]=='a' && strncmp(zLine,"atd",3)==0
- && zLine[3]==zPhone[0] && strncmp(&zLine[3],zPhone,strlen(zPhone))==0 ){
- /* Skip the echo of the dial command to the modem */
- zLine[0] = 0;
- continue;
- }
- if( nChar==0 ){
- nTimeout++;
- if( timeout==dial_timeout ){
- WriteChatStat(iRec,"Modem could not connect at");
- break;
- }else if( (nTimeout>2 && *Lookup(iRec,"autostart","yes")!='n')
- || zChat[0]=='n' ){
- rc = 0;
- break;
- }else{
- ChatSend(chatDelay,0,"\r",0);
- continue;
- }
- }
- timeout = atoi(Lookup(iRec,"chattimeout",CHAT_TIMEOUT));
- nTimeout = 0;
- for(i=0; i<=9; i++){
- if( zExpect[i]==0 || zReply[i]==0 ) continue;
- if( Match7(zLine,zExpect[i]) ){
- zLine[0] = 0;
- if( strcmp(zReply[i],"ACCEPT")==0 ){
- rc = 0;
- goto chat_done;
- }else if( strcmp(zReply[i],"FAIL")==0 ){
- goto chat_done;
- }else{
- ChatSend(chatDelay,0,zReply[i],"\r",0);
- nTimeout = 0;
- timeout = 3;
- break;
- }
- }
- }
- if( Match(zLine,"BUSY") ){
- WriteChatStat(iRec,"Busy signal at");
- break;
- }else if( Match(zLine,"NO CARRIER") ){
- WriteChatStat(iRec,"No carrier at");
- break;
- }else if( Match(zLine,"NO DIALTONE") ){
- WriteChatStat(iRec,"No dialtone at");
- break;
- }else if( Match(zLine,"NO ANSWER") ){
- WriteChatStat(iRec,"Ringing but no answer at");
- break;
- }else if( Match7(zLine,"ogin:") || Match7(zLine,"rname:")
- || Match7(zLine,"-on:") || Match7(zLine,"serid:") ){
- zVal = Lookup(iRec,"user","anonymous");
- ChatSend(chatDelay,0,zVal,"\r",0);
- zLine[0] = 0;
- }else if( Match7(zLine,"ssword:") ){
- zVal = Lookup(iRec,"password","");
- ChatSend(chatDelay,1,zVal,"\r",0);
- zLine[0] = 0;
- }else if( Match(zLine,"~\377}#") || Match(zLine,"\300!}!") ){
- rc = 0;
- break;
- }else if( Match(zLine,"CONNECT") && zChat[0]=='n' ){
- rc = 0;
- break;
- #if 0
- }else if( Match7(zLine,"destination:") || Match7(zLine,"response:") ){
- ChatSend(chatDelay,0,"ppp\r",0);
- zLine[0] = 0;
- #endif
- }else if( IsPrompt(zLine) ){
- ChatSend(chatDelay,0,"ppp\r",0);
- zLine[0] = 0;
- }else{
- /* Ignore it */
- }
- }
-
- chat_done:
- if( transcript ){
- WriteTimestamp();
- fprintf(transcript, rc ? " Fail\n" : " Accept\n");
- fclose(transcript);
- }
- fcntl(0,F_SETFL,flags);
- tcsetattr(0,TCSANOW,&tio_0_saved);
- tcsetattr(1,TCSANOW,&tio_1_saved);
- return rc;
- }
-
- /* Print status information for a given service.
- */
- static void PrintStatus(int iRec){
- char *zService;
- char *zStatus;
- char *zDiald;
- int pidDiald;
- char zBuf[30];
- char zFile[sizeof(DB_DIR)+100];
-
- if( iRec<0 || iRec>=nRecord ) return;
- sprintf(zFile,"%s/diald.%d",DB_DIR,iRec);
- zDiald = ReadFile(zFile);
- if( zDiald==0 || (pidDiald=atoi(zDiald))<=0
- || kill(pidDiald,0)!=0 ){
- zDiald = "";
- }else{
- zDiald = "(diald running) ";
- }
- sprintf(zBuf,"service #%d",iRec);
- zService = Lookup(iRec,"service",zBuf);
- sprintf(zFile,"%s/status.%d",DB_DIR,iRec);
- zStatus = ReadFile(zFile);
- if( zStatus==0 ){
- printf("%s: %sStatus Unknown\n",zService, zDiald);
- }else{
- printf("%s: %s%s",zService, zDiald, zStatus);
- free( zStatus );
- }
- }
-
- /*
- ** Return true if the given string contains a space or $ character
- ** and therefore needs to be quoted for the shell.
- */
- static int NeedQuote(char *z){
- while( *z ){
- if( *z==' ' || *z=='$' || *z=='"' ) return 1;
- z++;
- }
- return 0;
- }
-
- /*
- ** Open the transcript for record N and write the given argv[] string
- ** to it.
- */
- static void WriteArgvToTranscript(int iRec, char **argv){
- int size;
- int i;
- char *zStr, *z;
- char zFile[sizeof(DB_DIR)+20];
-
- size = 0;
- for(i=0; argv[i]; i++){
- size += strlen(argv[i]) + 3;
- }
- zStr = z = malloc( size );
- if( zStr ){
- for(i=0; argv[i]; i++){
- if( NeedQuote(argv[i]) ){
- *z++ = '\'';
- strcpy(z,argv[i]);
- z += strlen(z);
- *z++ = '\'';
- }else{
- strcpy(z,argv[i]);
- z += strlen(z);
- }
- if( argv[i+1] ){
- *z++ = ' ';
- }
- }
- *z = 0;
- sprintf(zFile,"%s/transcript.%d", DB_DIR, iRec);
- WriteToFile(zFile, 0600, "%s\n", zStr);
- }
- }
-
- /* Check to see if diald is already running. Return a process ID
- ** for diald if it is running. Or return 0 if there is no diald
- ** running.
- */
- static int DialdPid(int iRec){
- char *zDiald;
- int pidDiald;
- char zDialdFile[sizeof(DB_DIR)+100];
-
- sprintf(zDialdFile, "%s/diald.%d", DB_DIR, iRec);
- zDiald = ReadFile(zDialdFile);
- if( zDiald==0 ) return 0;
- pidDiald = atoi(zDiald);
- free(zDiald);
- if( pidDiald==0 ){
- unlink(zDialdFile);
- return 0;
- }
- if( kill(pidDiald,0) ){
- unlink(zDialdFile);
- return 0;
- }
- return pidDiald;
- }
-
- /*
- ** Shutdown the diald process
- */
- static int StopDiald(int iRec){
- int pidDiald;
-
- if( (pidDiald = DialdPid(iRec))!=0 ){
- kill(pidDiald,SIGTERM);
- }
- return 0;
- }
-
- /* Attempt to hang up the given port.
- */
- static void Hangup(int iRec){
- char *zDev;
- char *zPpp;
- int pidPpp = -1;
- int pidDiald = -1;
- int fd;
- int tries;
- struct termios ios;
- char zFile[sizeof(DB_DIR)+20];
-
- WriteStatus(iRec,"hangup at");
-
- /* Send a SIGINT to any diald process that is running.
- ** This is suppose to make diald hangup the line.
- */
- pidDiald = DialdPid(iRec);
- if( pidDiald ){
- kill(pidDiald,SIGINT);
- return;
- }
-
- /* We only reach this point if diald is not running.
- ** Send a SIGTERM to any running ppp process. This is suppose
- ** to make ppp hang up the line and exit
- */
- sprintf(zFile,"%s/ppp.%d", DB_DIR, iRec);
- zPpp = ReadFile(zFile);
- if( zPpp && (pidPpp=atoi(zPpp))>0 ){
- kill(pidPpp,SIGTERM);
- sleep(1);
- }
-
- /* Try to open the TTY. Try as many as three times waiting for
- ** one second between each attempt. After the second failed attempt,
- ** send a SIGKILL to any diald or ppp process out there.
- */
- zDev = Lookup(iRec,"tty","/dev/modem");
- tries = 0;
- while( (fd=open(zDev,O_RDWR|O_NONBLOCK))<0 && tries<2 ){
- if( tries==1 ){
- if( pidPpp>0 ){
- kill(pidPpp, SIGKILL);
- }else if( pidDiald>0 ){
- kill(pidDiald, SIGKILL);
- }
- }
- tries++;
- sleep(1);
- }
-
- /* Change the buad rate of the TTY to 0. This is suppose to make
- ** the DTR line go low, which should make the modem hangup.
- */
- if( fd>=0 ){
- tcgetattr(fd, &ios);
- cfsetospeed(&ios, B0);
- tcsetattr(fd, TCSANOW, &ios);
- close(fd);
- }
- }
-
- /*
- ** Write into the given buffer the name of a file that will contain
- ** the PID of the PPP process that is calling on serial device zDev.
- ** Assume the size of the buffer into which we write is at least
- ** sizeof(DB_DIR)+100.
- **
- ** The zDev probably contains '/' characters. These must be converted
- ** to something different.
- */
- static void MakeDeviceFile(char *zFile, char *zDev){
- int i;
- sprintf(zFile,"%s/device%.80s", DB_DIR, zDev);
- i = strlen(DB_DIR) + 5;
- while( zFile[i] ){
- if( zFile[i]=='/' ){ zFile[i] = '.'; }
- i++;
- }
- }
-
- /*
- ** Given a modem device name, find the service number.
- */
- static int DeviceToRec(char *zDev){
- char *z;
- int iRec;
- char zFile[sizeof(DB_DIR)+100];
-
- MakeDeviceFile(zFile, zDev);
- z = ReadFile(zFile);
- if( z==0 || (iRec=atoi(z))<0 || iRec>=nRecord ){
- for(iRec=0; iRec<nRecord; iRec++){
- z = Lookup(iRec,"tty","/dev/modem");
- if( strcmp(z,zDev)==0 ) break;
- }
- if( iRec>nRecord ) iRec = FIND_ERROR;
- }
- return iRec;
- }
-
- /* This routine is called when "pppd" executes "ip-up".
- */
- static void IpUp(char **argv){
- int iRec;
- int i;
- char zFile[sizeof(DB_DIR)+20];
-
- iRec = DeviceToRec(argv[1]);
- if( iRec<0 ) return;
- WriteStatus(iRec,"%s %s to %s up since",argv[0],argv[3],argv[4]);
- sprintf(zFile,"%s/pid.%d", DB_DIR, iRec);
- unlink(zFile);
- for(i=0; i<=9; i++){
- char *zNet;
- char zRoute[1000];
- char zLabel[20];
- sprintf(zLabel,"route%d",i);
- zNet = Lookup(iRec,zLabel,0);
- if( zNet==0 ) continue;
- sprintf(zRoute,"/sbin/route add -net %.100s %.100s", zNet, argv[0]);
- system(zRoute);
- }
- }
-
- /* This routine is called when "pppd" executes "ip-down".
- */
- static void IpDown(char **argv){
- int iRec;
- char zFile[sizeof(DB_DIR)+80];
-
- iRec = DeviceToRec(argv[1]);
- if( iRec<0 ) return;
- WriteStatus(iRec,"down since");
- MakeDeviceFile(zFile, argv[1]);
- unlink(zFile);
- sprintf(zFile,"%s/ppp.%d", DB_DIR, iRec);
- unlink(zFile);
- }
-
- /*
- ** This routine creates a session log for the most recent login
- ** attempt. The session log consists of two data sources:
- **
- ** 1. The modem dialing and logon transcript.
- **
- ** 2. All messages written to the /var/log/messages file by pppd.
- **
- ** The session log is overwritten after every logon attempt.
- */
- static void MakeSessionLog(time_t startTime, int pid, int iRec){
- FILE *out;
- char *z;
- struct tm *pTm;
- char zFile[sizeof(DB_DIR)+100];
- char zCmd[sizeof(DB_DIR)+100];
-
- out = fopen(SESSIONLOG,"w");
- if( out==0 ) return;
- fchmod(fileno(out),0644);
- fprintf(out,"This is a diagnostic log of the most recent login\n"
- "attempt by eznet.\n\n");
- z = Lookup(iRec,"service",0);
- if( z ){
- fprintf(out, " ISP Name: \"%s\"\n", z);
- }
- pTm = localtime(&startTime);
- fprintf(out," Call Initiated: %s\n", asctime(pTm));
- sprintf(zFile,"%s/transcript.%d", DB_DIR, iRec);
- z = ReadFile(zFile);
- if( z ){
- int i;
- for(i=0; z[i] && z[i]!='\n'; i++){}
- fprintf(out,
- "The UNIX command used to initiate the connection attempt was: \n\n"
- "%.*s\n\n",
- i, z);
- if( z[i] ){ i++; }
- fprintf(out,"The interaction with the modem was as follows:\n\n"
- "%s\n", &z[i]);
- free(z);
- }else{
- fprintf(out,"The modem transcript could not be located!\n\n");
- }
- fprintf(out,
- "The following messages were written to the system log\n"
- "(in /var/log/messages) by pppd as it attempted to negotiate\n"
- "a PPP connection.");
- z = Lookup(iRec,"debug","n");
- if( z && *z=='y' ){
- fprintf(out," Details may be omitted by clearing the\n"
- "\"debug=%s\" property.\n\n", z);
- }else{
- fprintf(out," To see more detail, set the \"debug=yes\"\n"
- "property and reattempt the logon.\n\n");
- }
- fclose(out);
- sprintf(zCmd,"tail -200 /var/log/messages | grep 'pppd.%d.' >>%s",
- pid, SESSIONLOG);
- system(zCmd);
- }
-
- /* This routine is called in order to attempt to establish
- ** a connection. Return 0 if successful and non-zero if we fail.
- */
- static int Dial(int iRec){
- char *zPw;
- char *zDevice;
- char *zUser;
- char *zPpp;
- char *zService;
- char *zIdle;
- int pidPpp;
- int pidDiald;
- int rc;
- int isup = 1;
- time_t startTime;
- char zDeviceFile[sizeof(DB_DIR)+100];
- char zChatStat[sizeof(DB_DIR)+100];
- char zPidFile[sizeof(DB_DIR)+100];
- char zConnect[200];
- char zServiceBuf[50];
-
- /* Check to see if we are already running directly.
- */
- startTime = time(0);
- sprintf(zPidFile, "%s/pid.%d", DB_DIR, iRec);
- zPpp = ReadFile(zPidFile);
- if( zPpp && (pidPpp=atoi(zPpp))>0 && kill(pidPpp,0)==0 ){
- return 0;
- }
-
- /* Check to see if diald is running. If it is, then
- ** just send it a SIGUSR1 to bring the link up.
- */
- if( (pidDiald = DialdPid(iRec))>0 ){
- kill(pidDiald,SIGUSR1);
- return 0;
- }
-
- /* Initialize the ipup, ipdown, chap-secrets and pap-secrets files.
- */
- SetIpUpDown("up");
- SetIpUpDown("down");
- sprintf(zServiceBuf,"x%d",iRec);
- zService = Lookup(iRec,"service",zServiceBuf);
- zUser = Lookup(iRec,"user","anonymous");
- zPw = Lookup(iRec, "password", "*");
- if( zPw ){
- SetSecrets("pap-secrets",zService,zUser,zPw);
- SetSecrets("chap-secrets",zService,zUser,zPw);
- }
- zDevice = Lookup(iRec, "tty", "/dev/modem");
-
- /* Set the device file to the current ordinal number. This is needed
- ** by the ipup and ipdown scripts.
- */
- MakeDeviceFile(zDeviceFile, zDevice);
- WriteToFile(zDeviceFile, 0644, "%d\n", iRec);
- WriteToFile(zPidFile, 0644, "%d\n", getpid());
-
- /* Set the status to dialing.
- */
- WriteStatus(iRec, "dialing since");
-
- /* The child does the work. The parent waits for it to finish.
- */
- rc = fork();
- if( rc<0 ){
- WriteStatus(iRec,"fork failed");
- return 1;
- }
- if( rc==0 ){
- /* The child process */
- int argc = 0;
- char *z;
- int i;
- char zLabel[100];
- char *argv[200];
-
- argv[argc++] = Lookup(iRec, "pppd", PPP_EXE);
- argv[argc++] = zDevice;
- argv[argc++] = Lookup(iRec,"baud","115200");
- argv[argc++] = "connect";
- sprintf(zConnect,SELF " chat %d",iRec);
- argv[argc++] = zConnect;
- z = Lookup(iRec, "defaultroute", "y");
- if( *z=='y' ){
- argv[argc++] = "defaultroute";
- }
- argv[argc++] = "lock";
- argv[argc++] = "modem";
- argv[argc++] = "mtu";
- argv[argc++] = Lookup(iRec,"mtu","552");
- argv[argc++] = "mru";
- argv[argc++] = Lookup(iRec,"mru","552");
- z = Lookup(iRec,"debug",0);
- if( z && *z=='y' ){
- argv[argc++] = "debug";
- }
- argv[argc++] = "crtscts";
- argv[argc++] = "-detach";
- z = Lookup(iRec,"persist","no");
- if( *z=='y' ){
- argv[argc++] = "persist";
- }else{
- zIdle = Lookup(iRec,"idle","300");
- if( atoi(zIdle)>0 ){
- z = Lookup(iRec,"pppversion",DFLT_PPP_VERSION);
- argv[argc++] = strcmp(z,"2.3")<0 ? "idle-disconnect" : "idle";
- argv[argc++] = zIdle;
- }
- }
- argv[argc++] = "user";
- argv[argc++] = zUser;
- argv[argc++] = "remotename";
- argv[argc++] = zService;
- for(i=0; i<10; i++){
- sprintf(zLabel,"pppopt%d",i);
- z = Lookup(iRec,zLabel,0);
- if( z==0 ) break;
- argv[argc++] = z;
- }
- argv[argc] = 0;
- WriteArgvToTranscript(iRec,argv);
- execv(argv[0],argv);
- exit(0);
- }else{
- /* The parent process */
- char zPppFile[sizeof(DB_DIR)+20];
-
- sprintf(zPppFile,"%s/ppp.%d", DB_DIR, iRec);
- WriteToFile(zPppFile,0644,"%d\n",rc);
- while( access(zPidFile,0)==0 ){
- int status;
- if( waitpid(rc,&status,WNOHANG)>0 ){
- isup = 0;
- break;
- }
- sleep(1);
- }
- sprintf(zChatStat,"%s/chatstat.%d", DB_DIR, iRec);
- if( !isup ){
- char *z = ReadFile(zChatStat);
- if( z ){
- WriteStatus(iRec,z);
- }else{
- WriteStatus(iRec,"pppd failure at");
- }
- unlink(zDeviceFile);
- unlink(zPppFile);
- }
- unlink(zPidFile);
- unlink(zChatStat);
- MakeSessionLog(startTime, rc,iRec);
- PrintStatus(iRec);
- }
- return !isup;
- }
-
-
- /* This routine is called in order to active the diald daemon.
- */
- static int StartDiald(int iRec){
- char *zPpp;
- char *zDiald;
- char *zPw;
- char *zUser;
- char *zService;
- char *z;
- int pidPpp;
- int pidDiald;
- int rc;
- int i;
- FILE *out;
- char zConfFile[sizeof(DB_DIR)+100];
- char zPidFile[sizeof(DB_DIR)+20];
- char zDialdFile[sizeof(DB_DIR)+100];
- char zServiceBuf[50];
-
- /* Check to see if diald is already running.
- */
- sprintf(zDialdFile, "%s/diald.%d", DB_DIR, iRec);
- zDiald = ReadFile(zDialdFile);
- if( zDiald && (pidDiald=atoi(zDiald))>0 && kill(pidDiald,0)==0 ){
- return 0;
- }
-
- /* Check to see if we are already running directly. If so, then
- ** do a hangup before continuing.
- */
- sprintf(zPidFile, "%s/pid.%d", DB_DIR, iRec);
- zPpp = ReadFile(zPidFile);
- if( zPpp && (pidPpp=atoi(zPpp))>0 && kill(pidPpp,0)==0 ){
- Hangup(iRec);
- }
-
- /* Initialize the chap-secrets and pap-secrets files.
- */
- sprintf(zServiceBuf,"x%d",iRec);
- zService = Lookup(iRec,"service",zServiceBuf);
- zUser = Lookup(iRec,"user","anonymous");
- zPw = Lookup(iRec, "password", "*");
- if( zPw ){
- SetSecrets("pap-secrets",zService,zUser,zPw);
- SetSecrets("chap-secrets",zService,zUser,zPw);
- }
-
- /* Create the diald configuration script.
- */
- sprintf(zConfFile, "%s/diald.conf.%d", DB_DIR, iRec);
- out = fopen(zConfFile,"w");
- if( out==0 ){
- WriteStatus(iRec, "configuration failed");
- return 1;
- }
- fprintf(out,"mode ppp\n");
- fprintf(out,"device %s\n", Lookup(iRec,"tty","/dev/modem"));
- fprintf(out,"connect '" SELF " chat %d'\n", iRec);
- fprintf(out,"speed %s\n", Lookup(iRec,"baud","115200"));
- z = Lookup(iRec,"defaultroute","y");
- if( *z=='y' ){
- fprintf(out,"defaultroute\n");
- }
- fprintf(out,"local %s\n", Lookup(iRec,"local","127.0.0.100"));
- fprintf(out,"remote %s\n", Lookup(iRec,"remote","127.0.0.101"));
- fprintf(out,
- "lock\n"
- "modem\n"
- "crtscts\n"
- "-reroute\n"
- "dynamic\n"
- "-daemon\n"
- );
- fclose(out);
-
- /* Fire up the diald process
- */
- rc = fork();
- if( rc<0 ){
- WriteStatus(iRec,"fork failed");
- return 1;
- }
- if( rc==0 ){
- /* The child process */
- int argc = 0;
- char *argv[30];
-
- argv[argc++] = Lookup(iRec, "diald", DIALD_EXE);
- argv[argc++] = "-f";
- argv[argc++] = zConfFile;
- argv[argc++] = "--";
- argv[argc++] = "remotename";
- argv[argc++] = zService;
- argv[argc++] = "user";
- argv[argc++] = zUser;
- for(i=0; i<10; i++){
- char zLabel[100];
- sprintf(zLabel,"pppopt%d",i);
- z = Lookup(iRec,zLabel,0);
- if( z==0 ) break;
- argv[argc++] = z;
- }
- argv[argc] = 0;
- WriteArgvToTranscript(iRec,argv);
- close(0);
- close(1);
- close(2);
- open("/dev/null",O_RDWR);
- open("/dev/null",O_RDWR);
- open("/dev/null",O_RDWR);
- execv(argv[0],argv);
- exit(0);
- }
- /* The parent process */
- WriteToFile(zDialdFile,0644,"%d\n",rc);
- sleep(1);
- if( kill(rc,0) ){
- WriteStatus(iRec,"diald startup failed at");
- rc = 1;
- }else{
- WriteStatus(iRec,"diald started at");
- rc = 0;
- }
- return rc;
- }
-
- /*
- ** Given a configuration file entry, return a "safe" value for
- ** this entry. If the entry is the password and the real user
- ** is anything other than root, return "*********".
- */
- static char *SafeValue(ConfEntry *p){
- char *zVal;
- if( strcmp(p->zLabel,"password")==0 && getuid()!=0 ){
- zVal = "**********";
- }else{
- zVal = p->zValue;
- }
- return zVal;
- }
-
- /* Print a usage comment and die. A call to this
- ** routine never returns.
- */
- static void usage(char *argv0){
- fprintf(stderr,
- "User commands:\n"
- " %s add ORDINAL FIELD=VALUE...\n"
- " %s change ORDINAL|SERVICE ?FIELD=VALUE?...\n"
- " %s delete ORDINAL|SERVICE|IP\n"
- " %s dialdoff ORDINAL|IP|DEVICE\n"
- " %s dialdon ORDINAL|IP|DEVICE\n"
- " %s down ORDINAL|IP|DEVICE|all\n"
- " %s list ?ORDINAL|SERVICE?\n"
- " %s log\n"
- " %s move ORDINAL ORDINAL\n"
- " %s names\n"
- " %s status\n"
- " %s up SERVICE|IP|ORDINAL\n"
- "\n"
- "Commands for internal use only:\n"
- " %s chat ORDINAL\n"
- " %s ipdown INTERFACE DEVICE SPEED LOCAL-IP REMOTE-IP\n"
- " %s ipup INTERFACE DEVICE SPEED LOCAL-IP REMOTE-IP\n"
- "\n"
- "Field names:\n"
- " phone = phone number for modem to dial\n"
- " user = user login name\n"
- " password = login password\n"
- " tty = serial port for the modem\n"
- " baud = baud rate\n"
- " service = name of ISP\n"
- " chat = \"no\" to ignore \"login:\" prompts, etc.\n"
- " autostart = \"no\" to prevent starting pppd if no \"login:\" seen\n"
- " pppversion = what version of pppd is being used\n"
- " debug = \"yes\" to turn on pppd debugging\n"
- " expectN = Nth extra expect string (N between 1 and 9)\n"
- " replyN = Reply to issue when expectN is seen\n"
- " initN = Nth modem initialization string (N between 1 and 9)\n"
- " diald = name of diald executable\n"
- " pppd = name of pppd executable\n"
- " local = local IP address for diald slip link\n"
- " remote = remote IP address for diald slip link\n"
- " idle = number of seconds for idle timeout\n"
- " persist = \"yes\" for a permanent connection\n"
- " defaultroute = \"no\" to prevent creating a default route\n"
- " pppoptN = Nth extra parameter to pppd\n"
- " routeN = Add a route to the specified network when pppd comes up\n"
- " ip = network that this service gives access to\n"
- " netmask = netmask for the ip= network\n"
- " dialtimeout = time allowed for the modem to connect\n"
- " chattimeout = time allowed for chat responses\n",
-
- argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0,
- argv0, argv0, argv0, argv0, argv0, argv0, argv0
- );
- exit(1);
- }
-
-
- int main(int argc, char **argv){
- int iRec;
- int rc = 0;
-
- if( argc<2 ) usage(argv[0]);
- if( access(DB_DIR,0) ){
- mkdir(DB_DIR,0755);
- chown(DB_DIR,0,0);
- if( access(DB_DIR,0) ){
- fprintf(stderr,"%s: missing directory \"%s\"\n", argv[0], DB_DIR);
- exit(1);
- }
- }
- ReadDb();
- if( (argc==2 || argc==3) && strcmp(argv[1],"list")==0 ){
- int iRec = FindRecord(argv[2]);
- Unprivileged();
- if( iRec<0 || iRec>=nRecord ){
- int i;
- for(i=0; i<nRecord; i++){
- ConfEntry *p = aRecord[i] = sort(aRecord[i]);
- if( p==0 ) continue;
- printf("Record %d:\n",i);
- for(; p; p=p->next){
- printf(" %s = %s\n",p->zLabel, SafeValue(p));
- }
- }
- }else{
- ConfEntry *p = aRecord[iRec] = sort(aRecord[iRec]);
- for(; p; p=p->next){
- printf(" %s = %s\n",p->zLabel, SafeValue(p));
- }
- }
- }else if( argc==2 && strcmp(argv[1],"log")==0 ){
- char *z;
- Unprivileged();
- z = ReadFile(SESSIONLOG);
- if( z ){
- printf("%s",z);
- }
- }else if( (argc==2 || argc==3 ) && strcmp(argv[1],"tcllist")==0 ){
- int i;
- Unprivileged();
- for(i=0; i<nRecord; i++){
- ConfEntry *p = aRecord[i] = sort(aRecord[i]);
- if( p==0 ) continue;
- for(; p; p=p->next){
- printf("set eznet(%d:%s) ",i,p->zLabel);
- WriteTcl(stdout,SafeValue(p));
- printf("\n");
- }
- }
- }else if( argc==2 && strcmp(argv[1],"names")==0 ){
- int i;
- Unprivileged();
- for(i=0; i<nRecord; i++){
- char *z = Lookup(i,"service",0);
- if( z ){
- printf("%s\n",z);
- }else{
- printf("%d\n",i);
- }
- }
- }else if( argc>=3 && strcmp(argv[1],"add")==0 ){
- int iRec;
- Unprivileged();
- iRec = FindRecord(argv[2]);
- if( iRec==FIND_ERROR ){
- AddEntries(nRecord, argc-2, argv+2);
- }else if( iRec>=nRecord ){
- AddEntries(nRecord, argc-3, argv+3);
- }else{
- AddEntries(nRecord, argc-3, argv+3);
- MoveRecord(nRecord, iRec);
- }
- WriteDb();
- }else if( argc==3 && strcmp(argv[1],"delete")==0 ){
- int iRec = FindRecord(argv[2]);
- Unprivileged();
- if( iRec==FIND_ALL ){
- nRecord = 0;
- }else if( iRec==FIND_ERROR ){
- usage(argv[0]);
- }else{
- MoveRecord(iRec,nRecord-1);
- aRecord[nRecord-1] = 0;
- }
- WriteDb();
- }else if( argc>=4 && strcmp(argv[1],"change")==0 ){
- int iRec;
- Unprivileged();
- iRec = FindRecord(argv[2]);
- if( iRec==FIND_ALL ){
- usage(argv[0]);
- }else{
- if( iRec==FIND_ERROR ){
- iRec = nRecord==1 ? 0 : nRecord;
- }
- AddEntries(iRec, argc-3, argv+3);
- }
- WriteDb();
- }else if( argc==4 && strcmp(argv[1],"move")==0 ){
- int from, to;
- Unprivileged();
- if( argc!=4 ) usage(argv[0]);
- from = GetInt(argv[2]);
- to = GetInt(argv[3]);
- if( from>=0 && to>=0 ) MoveRecord(from,to);
- WriteDb();
- }else if( argc==3 && strcmp(argv[1],"chat")==0 ){
- iRec = FindRecord(argv[2]);
- if( iRec<0 ) usage(argv[0]);
- rc = Chat(iRec);
- }else if( (argc==2 || argc==3) && strcmp(argv[1],"status")==0 ){
- iRec = FindRecord(argv[2]);
- Unprivileged();
- if( iRec<0 ){
- for(iRec=0; iRec<nRecord; iRec++){
- PrintStatus(iRec);
- }
- }else{
- PrintStatus(iRec);
- }
- }else if( (argc==2 || argc==3) && strcmp(argv[1],"down")==0 ){
- iRec = FindRecord(argv[2]);
- /* Unprivileged(); --- Yeah. Let anybody do a hangup... */
- if( iRec==FIND_ALL ){
- system("/bin/kill -TERM `/sbin/pidof pppd` >/dev/null 2>&1");
- system("/bin/kill -TERM `/sbin/pidof diald` >/dev/null 2>&1");
- for(iRec=0; iRec<nRecord; iRec++){
- Hangup(iRec);
- }
- }else{
- Hangup(iRec);
- }
- }else if( argc==7 && strcmp(argv[1],"ipup")==0 ){
- Unprivileged();
- IpUp(&argv[2]);
- }else if( argc==7 && strcmp(argv[1],"ipdown")==0 ){
- Unprivileged();
- IpDown(&argv[2]);
- }else if( (argc==2 || argc==3) && strcmp(argv[1],"up")==0 ){
- if( access(SELF,X_OK)!=0 ){
- fprintf(stderr,"eznet must be installed as \"" SELF "\"\n");
- exit(1);
- }
- iRec = FindRecord(argv[2]);
- if( iRec<0 ){ usage(argv[0]); }
- rc = Dial(iRec);
- }else if( (argc==3 || argc==2) && strcmp(argv[1],"dialdon")==0 ){
- if( access(SELF,X_OK)!=0 ){
- fprintf(stderr,"eznet must be installed as \"" SELF "\"\n");
- exit(1);
- }
- iRec = FindRecord(argv[2]);
- if( iRec<0 ){ usage(argv[0]); }
- rc = StartDiald(iRec);
- }else if( (argc==3 || argc==2) && strcmp(argv[1],"dialdoff")==0 ){
- iRec = FindRecord(argv[2]);
- if( iRec<0 ){ usage(argv[0]); }
- rc = StopDiald(iRec);
- }else if( argc==3 && strcmp(argv[1],"delete")==0 ){
- Unprivileged();
- iRec = FindRecord(argv[2]);
- if( iRec>=0 && iRec<nRecord ){
- MoveRecord(iRec, nRecord-1);
- nRecord--;
- WriteDb();
- }
- }else{
- Unprivileged();
- usage(argv[0]);
- }
- return rc;
- }
-